/**
 * The model of the Item table, maps the items to the table rows and viceversa.
 * 
 * @author remo.lemma@lu.unisi.ch
 */

package ch.unisi.inf.projects.java.uom.gui.table.item;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.table.DefaultTableModel;

import ch.unisi.inf.projects.java.uom.Constants;
import ch.unisi.inf.projects.java.uom.Parser;
import ch.unisi.inf.projects.java.uom.elements.Element;
import ch.unisi.inf.projects.java.uom.elements.Item;
import ch.unisi.inf.projects.java.uom.exceptions.UOMException;
import ch.unisi.inf.projects.java.uom.gui.table.UOMItemJTable;

public class UOMItemTableModel extends DefaultTableModel
{
	/** We are not going to serialize this class atm */
    private static final long serialVersionUID = -1L;
    
    final UOMItemJTable table;
    
    final List<Item> items;
            
    public UOMItemTableModel (final UOMItemJTable table)
    {
    	this.table = table;
    	items = new ArrayList<Item>();
    }
	
    public void clear ()
    {
    	for (int i = 0; i < this.getRowCount(); i++)
    		this.removeRow(i);
    	this.setRowCount(0);
    	items.clear();
    }
    
    public void addRow (final Item i)
    {
    	final Object identifier;
    	if (table.getSortedColumn() != null)
    		identifier = table.getSortedColumn().getIdentifier();
    	else
    		identifier = null;
   		if (findRow(i) != -1)
   			return;
   		else if (items.size() == 0 && table.getColumnExt(Constants.ITEM_PRIMARY_KEY.value()) == null)
			this.addColumn(Constants.ITEM_PRIMARY_KEY.value().toUpperCase());
			table.getColumnExt(Constants.ITEM_PRIMARY_KEY.value()).setVisible(false);
    	final Vector<Object> v = new Vector<Object>();
    	for (int j = 0; j < this.getColumnCount(); j++)
    	{
    		try {
    			final String colName = super.getColumnName(j);
				final String value = i.getField(colName);
    			if (colName.equals(Constants.ITEM_CATEGORY_FIELD.value()))
    				v.add(i.getItemClass().getName());
    			else if (colName.equals(Constants.ITEM_HASPREVIEW_FIELD.value()))
    				v.add(i.getPreview() != null);
    			else if (Parser.instance().dbColumnTypeIsList(colName)) {
    				int elements = 0;
    				if (value != null && !value.equals(""))
    					elements = value.split(Constants.ITEM_PARSECHAR.value()).length;
    				v.add((elements + " elements")); 
    			}
    			else if (this.getColumnClass(j) == Boolean.class)
    				v.add((value != null) && (!value.equals("")));
    			else {
    				if (value == null || value.equals(""))
    					v.add("");
    				else
    					v.add(value);
    			}
    		}
    		catch (final Exception e) {
    			continue;
    		}
    	}
    	addRow(v);
    	items.add(i);
    	if (items.size() == 1 && identifier != null)
			table.toggleSortOrder(table.getColumn(identifier).getModelIndex());
    }
    
    @SuppressWarnings("unchecked")
	public void updateRow (final Element e)
    {
    	final int row = findRow(e);
    	if (row == -1)
    		return;
    	final Vector<Object> v = (Vector<Object>) this.getDataVector().elementAt(getRealIndex(row));
    	final Item i = getItem(row);
    	for (int j = 0; j < this.getColumnCount(); j++)
    	{
    		try {
    			final String colName = super.getColumnName(j);
    			if (colName.equals(Constants.ITEM_CATEGORY_FIELD.value()))
    				v.set(j,i.getItemClass().getName());
    			else if (colName.equals(Constants.ITEM_HASPREVIEW_FIELD.value()))
    				v.set(j,i.getPreview() != null);
    			else if (Parser.instance().dbColumnTypeIsList(colName)) {
    				int elements = 0;
    				final String value = i.getField(colName);
    				if (value != null && !value.equals(""))
    					elements = value.split(Constants.ITEM_PARSECHAR.value()).length;
    				v.set(j,(elements + " elements")); 
    			}
    			else if (this.getColumnClass(j) == Boolean.class)
    				v.set(j,(i.getField(colName) != null) && (!i.getField(colName).equals("")));
    			else
    				v.set(j,i.getField(colName));
    		}
    		catch (final Exception ex) {
    			continue;
    		}
    	}
    	this.fireTableRowsUpdated(row, row);
    }
    
    public void removeRow (final Element e)
    {
    	final int row = findRow(e);
    	if (row == -1)
    		return;
    	items.remove(getItem(row));
    	removeRow(getRealIndex(row));
    }
    
    public int findRow (final Element e)
    {
    	if (e == null)
    		return -1;
    	for (int i = 0; i < this.getRowCount(); i++) {
    		final Item item = getItem(i);
    		if (item == null)
    			continue;
    		else if (item.getName().equals(e.getName()))
    			return i;
    	}
    	return -1;
    }
    
    public Item getItem (final int row)
    {
    	int index;
    	try {
    		index = getRealIndex(row);
    	}
    	catch (final Exception e)
    	{
    		index = row;
    	}
    	try {
    		if (items.size() <= 0)
    			return null;
    		table.getColumnExt(Constants.ITEM_PRIMARY_KEY.value()).setVisible(true);
    		final Object id = this.getValueAt(index, table.getColumnModel().getColumnIndex(Constants.ITEM_PRIMARY_KEY.value()));
    		table.getColumnExt(Constants.ITEM_PRIMARY_KEY.value()).setVisible(false);
    		final Object cat = this.getValueAt(index, table.getColumnModel().getColumnIndex(Constants.ITEM_CATEGORY_FIELD.value()));
    		for (final Item item : items) {
    			if (id == null || cat == null)
    				continue;
    			else if (item.getId().equals(id.toString()) && item.getItemClass().getName().equals(cat.toString()))
    				return item;
    		}
    	}
    	catch (final Exception e) {
    		return null;
    	}
    	return null;
    }
    
    private int getRealIndex (final int row)
    {
    	final UOMFilterPipeline pipe = table.getPipeline();
    	return pipe.convertRowIndexToModel(row);
    }
    
    public Class<?> getColumnClass (final int col)
    {
    	final String realCol = super.getColumnName(col);
    	try {
    		if (realCol.equals(Constants.ITEM_HASPREVIEW_FIELD.value()) || (!Parser.instance().dbGetVarType(realCol).equals(Constants.ITEM_CLASS_STRING.value())
    				&& !Parser.instance().dbColumnTypeIsList(realCol)))
    			return Boolean.class;
    	}
    	catch (final UOMException ex)
    	{
    		// TODO
    	}
    			
        for (int i = 0; i < this.getRowCount(); i++) {
        	try {
        		if (this.getValueAt(i, col).toString().equals(""))
        			continue;
        		Double.parseDouble(this.getValueAt(i, col).toString());
        	}
        	catch (final NumberFormatException nfe)
        	{
        		return String.class;
        	}
        	catch (final NullPointerException npe)
        	{
        		return String.class;
        	}
        }
        return Double.class;
    }
    
    public boolean isCellEditable (final int row, final int col)
    {
    	return false;
    }
    
    public String getColumnName (final int col)
    {
    	try {
    		return Parser.instance().dbGetVarName(super.getColumnName(col));
    	}
    	catch (final UOMException ex) {
    		return super.getColumnName(col);
    	}
    }
    
    public String getRealColumnName (final int col)
    {
    	return super.getColumnName(col);
    }
}